package com.amap.search.service;

import cn.hutool.core.util.NumberUtil;
import com.amap.search.entity.db2022.FileRecord;
import com.amap.search.entity.db2022.PoiRecord;
import com.amap.search.entity.vo.AmapBaseResponse;
import com.amap.search.entity.vo.AmapPoiRequest;
import com.amap.search.entity.vo.AmapPoiRequest2;
import com.amap.search.entity.vo.AmapPoiResponse;
import com.amap.search.entity.vo.AmapPoiResponse2;
import com.amap.search.entity.vo.AmapWeatherRequest;
import com.amap.search.entity.vo.AmapWeatherResponse;
import com.amap.search.entity.vo.RoundRequestInfo;
import com.amap.search.mapper.db2022.FileRecordMapper;
import com.amap.search.mapper.db2022.PoiRecordMapper;
import com.amap.search.util.JacksonUtil;
import com.amap.search.util.RestHttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AmapHttpService {

    @Resource
    private RestHttpUtil restHttpUtil;

    @Value("${amap.search.url.weather:https://restapi.amap.com/v3/weather/weatherInfo}")
    private String weatherUrl;

    @Value("${amap.search.url.poi}")
    private String poiUrl;

    @Value("${amap.search.url.poi2}")
    private String poiUrl2;

    @Value("${amap.search.key}")
    private String key;

    @Resource
    private FileRecordMapper fileRecordMapper;

    @Resource
    private PoiRecordMapper poiRecordMapper;

    private final String SUCCESS_CODE = "10000";
    private final String USER_DAILY_QUERY_OVER_LIMIT = "10044";

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    /**
     * 通过高德地图API获取天气数据
     *
     * @param request
     * @return
     */
    public AmapWeatherResponse getWeatherInfo(AmapWeatherRequest request) {
        String key = getRoundKey();
        request.setCity(key);
        return restHttpUtil.getRequest(weatherUrl, request, AmapWeatherResponse.class);
    }

    public AmapPoiResponse getPoiInfo(AmapPoiRequest request) {
        if (StringUtils.isBlank(request.getTypes()) && StringUtils.isBlank(request.getKeywords())) {
            throw new RuntimeException("请输入查询关键字");
        }
        request.setKey(getRoundKey());
        AmapPoiResponse response = restHttpUtil.getRequest(poiUrl, request, AmapPoiResponse.class);
        checkResponseStatus(response);
        try {
            savePoiResponse(response);
        } catch (Exception e) {
            log.info("存储返回信息失败", e);
            throw new RuntimeException("请求成功， 保存数据失败");
        }
        return response;
    }

    public AmapPoiResponse2 getPoiInfo(AmapPoiRequest2 request) {
        if (request.getRegion() == null || request.getTypes() == null) {
            throw new RuntimeException("请输入查询关键字");
        }
        request.setKey(getRoundKey());
        AmapPoiResponse2 response = restHttpUtil.getRequest(poiUrl2, request, AmapPoiResponse2.class);
        checkResponseStatus(response);
        savePoiResponse(response);
        return response;
    }

    int searchRound = 0;
    public boolean searchPoiFromCity(String cityCode, String typeCode) {
        // 每次搜索20条， 高德地图一次搜索大于25条可能会出错
        int batch = 20;
        int page = 0;
        boolean hasNext = false;
        do {
            if (searchRound % 2 == 1) {
                AmapPoiRequest request = new AmapPoiRequest();
                request.setOffset(String.valueOf(batch));
                request.setPage(String.valueOf(page));
                request.setCity(cityCode);
                request.setTypes(typeCode);
                AmapPoiResponse response = getPoiInfo(request);
                hasNext = response.getPois() != null && response.getPois().size() == batch;
            } else {
                AmapPoiRequest2 request2 = new AmapPoiRequest2();
                request2.setPage_size(String.valueOf(batch));
                request2.setPage_num(String.valueOf(page));
                request2.setRegion(cityCode);
                request2.setTypes(typeCode);
                AmapPoiResponse2 response = getPoiInfo(request2);
                hasNext = response.getPois() != null && response.getPois().size() == batch;
            }
            page++;
            searchRound++;
        } while (hasNext);
        return true;
    }

    /**
     * 转换并存储poi数据
     *
     * @param response
     */
    @Transactional(rollbackFor = Exception.class, value = "savePoi")
    public int savePoiResponse(AmapPoiResponse response) throws ParseException {
        List<AmapPoiResponse.Poi> responsePois =  response.getPois();
        if(CollectionUtils.isEmpty(responsePois)){
            return 0;
        }
        // 根据poiId去重
        List<String> ids = responsePois.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<String> poiIdList = poiRecordMapper.queryPoiRecordPoiIdByIds(ids);
        if(CollectionUtils.isNotEmpty(poiIdList)){
            responsePois = responsePois.stream().filter(o -> !poiIdList.contains(o.getId())).collect(Collectors.toList());
        }

        // 转换数据以插入mysql
        List<PoiRecord> poiRecordList = constructPoiRecordList(responsePois);
        if(CollectionUtils.isNotEmpty(poiRecordList)) {
            return poiRecordMapper.insertBatch(poiRecordList);
        }
        return 0;
    }

    @Transactional(rollbackFor = Exception.class, value = "savePoi2")
    public int savePoiResponse(AmapPoiResponse2 response)  {
        List<AmapPoiResponse2.Poi> responsePois =  response.getPois();
        if(CollectionUtils.isEmpty(responsePois)){
            return 0;
        }
        // 根据poiId去重
        List<String> ids = responsePois.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<String> poiIdList = poiRecordMapper.queryPoiRecordPoiIdByIds(ids);
        if(CollectionUtils.isNotEmpty(poiIdList)){
            responsePois = responsePois.stream().filter(o -> !poiIdList.contains(o.getId())).collect(Collectors.toList());
        }

        // 转换数据以插入mysql
        List<PoiRecord> poiRecordList = constructPoiRecordList2(responsePois);
        if(CollectionUtils.isNotEmpty(poiRecordList)) {
            return poiRecordMapper.insertBatch(poiRecordList);
        }
        return 0;
    }

    private List<PoiRecord> constructPoiRecordList(List<AmapPoiResponse.Poi> poiList) throws ParseException {
        if (CollectionUtils.isEmpty(poiList)) {
            return null;
        }
        List<PoiRecord> result = new ArrayList<>();
        for (AmapPoiResponse.Poi poi : poiList) {
            if(poi.getAddress() == null){
                continue;
            }
            // 有图片或者有评价才入库
            if ((poi.getPhotos() != null && poi.getPhotos().size() > 0) ||
                    (poi.getBiz_ext() != null && NumberUtil.isDouble(String.valueOf(poi.getBiz_ext().getRating())))) {
                result.add(constructPoiRecordFormPoi(poi));
            }
        }
        return result;
    }

    /**
     * poi1.0接口返回内容转换为mysql实体
     */
    private PoiRecord constructPoiRecordFormPoi(AmapPoiResponse.Poi poi) throws ParseException {
        PoiRecord record = new PoiRecord();
        if (StringUtils.isNotBlank(poi.getTimestamp())) {
            record.setRecordDate(dateFormat.parse(poi.getTimestamp()));
        }
        record.setPoiId(poi.getId());
        String address = String.valueOf(poi.getAddress());
        record.setAddress(address.substring(0, Math.min(49, address.length())));
        String cost = String.valueOf(poi.getBiz_ext().getCost());
        if (NumberUtil.isDouble(cost)) {
            record.setCost(new BigDecimal(cost));
        }
        String rating = String.valueOf(poi.getBiz_ext().getRating());
        if (NumberUtil.isDouble(rating)) {
            record.setRating(new BigDecimal(rating));
        }
        record.setLocation(poi.getLocation());
        record.setAddressCode(poi.getAdcode());
        record.setName(poi.getName());
        String tel = String.valueOf(poi.getTel());
        if (tel != null && !"null".equals(tel)) {
            record.setTel(tel.length() > 39 ? tel.substring(0, 39) : tel);
        }
        String tag = String.valueOf(poi.getTag());
        if (tag != null && !"null".equals(tag)) {
            record.setTag(tag.length() > 90? tag.substring(0, 90) : tag);
        }
        record.setType(poi.getType());
        record.setTypeCode(poi.getTypecode());
        // 最多存三张照片
        List<AmapPoiResponse.Photo> photos = poi.getPhotos();
        List<String> idList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(photos)) {
            for (int i = 0; i < Math.min(photos.size(), 3); i++) {
                FileRecord fileRecord = new FileRecord();
                fileRecord.setFileType("PIC");
                fileRecord.setRelateTableName("poi_record");
                fileRecord.setFilePath(photos.get(i).getUrl());
                fileRecord.setFileName(record.getName());
                fileRecordMapper.insert(fileRecord);
                idList.add(fileRecord.getId().toString());
            }
            record.setPhotos(idList.stream().collect(Collectors.joining(",")));
        }
        return record;
    }

    private List<PoiRecord> constructPoiRecordList2(List<AmapPoiResponse2.Poi> poiList) {
        if (CollectionUtils.isEmpty(poiList)) {
            return null;
        }
        List<PoiRecord> result = new ArrayList<>();
        for (AmapPoiResponse2.Poi poi : poiList) {
            if(poi.getAddress() == null){
                continue;
            }
            // 有图片或者有评价才入库
            if ((poi.getPhotos() != null && poi.getPhotos().size() > 0) ||
                    (poi.getBusiness() != null && StringUtils.isNotEmpty(poi.getBusiness().getRating()))) {
                result.add(constructPoiRecordFormPoi2(poi));
            }
        }
        return result;
    }

    /**
     * poi2.0接口返回内容转换为mysql实体
     */
    private PoiRecord constructPoiRecordFormPoi2(AmapPoiResponse2.Poi poi) {
        PoiRecord record = new PoiRecord();
        record.setName(poi.getName());
        record.setPoiId(poi.getId());
        record.setLocation(poi.getLocation());
        record.setType(poi.getType());
        record.setTypeCode(poi.getTypecode());
        record.setAddressCode(poi.getAdcode());
        record.setAddress(poi.getAddress().substring(0, Math.min(49, poi.getAddress().length())));
        if (poi.getBusiness() != null) {
            String tel = poi.getBusiness().getTel();
            if(StringUtils.isNotEmpty(tel)) {
                record.setTel(tel.length() > 39 ? tel.substring(0, 39) : tel);
            }
            if(StringUtils.isNotEmpty(poi.getBusiness().getTag())) {
                record.setTag(poi.getBusiness().getTag().length() > 90 ? poi.getBusiness().getTag().substring(0,90): poi.getBusiness().getTag());
            }
            if (StringUtils.isNotEmpty(poi.getBusiness().getRating())) {
                record.setRating(new BigDecimal(poi.getBusiness().getRating()));
            }
            if (StringUtils.isNotEmpty(poi.getBusiness().getCost())) {
                record.setCost(new BigDecimal(poi.getBusiness().getCost()));
            }
        }
        // 最多存三张照片
        List<AmapPoiResponse2.Photos> photos = poi.getPhotos();
        ArrayList<String> idList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(photos)) {
            for (int i = 0; i < Math.min(photos.size(), 3); i++) {
                FileRecord fileRecord = new FileRecord();
                fileRecord.setRelateTableName("poi_record");
                fileRecord.setFileType("PIC");
                fileRecord.setFilePath(photos.get(i).getUrl());
                fileRecord.setFileName(record.getName());
                fileRecordMapper.insert(fileRecord);
                idList.add(fileRecord.getId().toString());
            }
            record.setPhotos(idList.stream().collect(Collectors.joining(",")));
        }
        return record;
    }


    private int keyRound = 0;
    public synchronized String getRoundKey() {
        String[] keyPool = key.split(",");
        keyRound = (keyRound + 1) % keyPool.length;
        return keyPool[keyRound];
    }

    public void checkResponseStatus(AmapBaseResponse response){
        if(!"10000".equals(response.getInfocode())){
            throw new RuntimeException("请求错误 : " + JacksonUtil.toJson(response));
        }
    }

}
